/*
 *  Copyright (c) 1999-2001 Vojtech Pavlik
 *
 *  USB HIDBP Mouse support
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
 */

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <linux/hid.h>

/* for apple IDs */
#ifdef CONFIG_USB_HID_MODULE
#include "../hid-ids.h"
#endif

/*
 * Version Information
 */
#define DRIVER_VERSION "v1.6"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB HID Boot Protocol mouse driver"
#define DRIVER_LICENSE "GPL"

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
MODULE_INFO(intree, "Y");

struct usb_mouse {
	char name[128];
	char phys[64];
	struct usb_device *usbdev;
	struct input_dev *dev;
	struct urb *irq;

	signed char *data;
	dma_addr_t data_dma;
};

static void usb_mouse_irq(struct urb *urb)
{
	struct usb_mouse *mouse = urb->context;
	signed char *data = mouse->data;
	struct input_dev *dev = mouse->dev;
	int status;

	switch (urb->status) {
	case 0:			/* success */
		break;
	case -ECONNRESET:	/* unlink */
	case -ENOENT:
	case -ESHUTDOWN:
		return;
	/* -EPIPE:  should clear the halt */
	default:		/* error */
		goto resubmit;
	}

	input_report_key(dev, BTN_LEFT,   data[0] & 0x01);
	input_report_key(dev, BTN_RIGHT,  data[0] & 0x02);
	input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
	input_report_key(dev, BTN_SIDE,   data[0] & 0x08);
	input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);

	input_report_rel(dev, REL_X,     data[1]);
	input_report_rel(dev, REL_Y,     data[2]);
	input_report_rel(dev, REL_WHEEL, data[3]);

	input_sync(dev);
resubmit:
	status = usb_submit_urb (urb, GFP_ATOMIC);
	if (status)
		dev_err(&mouse->usbdev->dev,
			"can't resubmit intr, %s-%s/input0, status %d\n",
			mouse->usbdev->bus->bus_name,
			mouse->usbdev->devpath, status);
}

static int usb_mouse_open(struct input_dev *dev)
{
	struct usb_mouse *mouse = input_get_drvdata(dev);

	mouse->irq->dev = mouse->usbdev;
	if (usb_submit_urb(mouse->irq, GFP_KERNEL))
		return -EIO;

	return 0;
}

static void usb_mouse_close(struct input_dev *dev)
{
	struct usb_mouse *mouse = input_get_drvdata(dev);

	usb_kill_urb(mouse->irq);
}

static void print_device_desc(struct usb_device_descriptor *desc)
{
	pr_err("%s:in %d.\n",__func__,__LINE__);
	pr_err("pid 0x%x, vid 0x%x\n", desc->idProduct, desc->idVendor);
}

static void usb_completion(struct urb *urb)
{
	pr_err("%s:in %d.\n",__func__,__LINE__);
	struct completion *urb_done_ptr = urb->context;

	pr_err("data 0x%x\n", ((char*)urb->transfer_buffer)[0]);
}

static void usb_completion2(struct urb *urb)
{
	pr_err("%s:in %d.\n",__func__,__LINE__);
	struct completion *urb_done_ptr = urb->context;

	complete(urb_done_ptr);
}

/* 发起一次控制传输. */
static void usb_ctrl_tran(struct usb_device *dev,
					u8 bRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength)
{
	pr_err("%s:in %d.\n",__func__,__LINE__);
	unsigned char *iobuf = NULL;
	dma_addr_t	iobuf_dma = 0;
	struct usb_ctrlrequest	*cr = NULL;
	struct urb *urb;
	int buf_size = wLength;
	int ctrl_pipe;
	int status = -1;
	struct completion urb_done;

	iobuf = usb_alloc_coherent(dev, buf_size, GFP_ATOMIC, &iobuf_dma);

	urb = usb_alloc_urb(0, GFP_KERNEL);

	cr = kmalloc(sizeof(*cr), GFP_KERNEL);

	ctrl_pipe = usb_rcvctrlpipe(dev, 0);

	cr->bRequestType = bRequestType;
	cr->bRequest = bRequest;
	cr->wValue = cpu_to_le16(wValue);
	cr->wIndex = cpu_to_le16(wIndex);
	cr->wLength = cpu_to_le16(wLength);

	usb_fill_control_urb(urb, dev, ctrl_pipe,
			 (unsigned char*)cr, iobuf, buf_size, 
			 usb_completion2, NULL);
	urb->transfer_flags = 0;

	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
	urb->transfer_dma = iobuf_dma;
	urb->context = &urb_done;

	init_completion(&urb_done);
	status = usb_submit_urb(urb, GFP_NOIO);
	if (status) {
		pr_err("%s:in %d. error\n",__func__,__LINE__);
		/* something went wrong */
	}
	wait_for_completion_interruptible(&urb_done);
}

/* 使用批量传输 从 usb设备接受 数据.
 *
 * @ep_num: 端点号, 需要为批量输入端点.*/
static void usb_bulk_recv(struct usb_device *dev,
				unsigned char *iobuf, int buf_size, dma_addr_t iobuf_dma, int ep_num)
{
	pr_err("%s:in %d.\n",__func__,__LINE__);
	struct urb *urb;
	int pipe;
	int status = -1;
	struct completion urb_done;

	urb = usb_alloc_urb(0, GFP_KERNEL);

	pipe = usb_rcvbulkpipe(dev, ep_num);

	usb_fill_bulk_urb(urb,
				     dev,
				     pipe,
					 iobuf,
					 buf_size,
					 usb_completion2,
				     &urb_done);

	urb->transfer_flags = 0;

	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
	urb->transfer_dma = iobuf_dma;

	init_completion(&urb_done);
	status = usb_submit_urb(urb, GFP_NOIO);
	if (status) {
		pr_err("%s:in %d. error\n",__func__,__LINE__);
		/* something went wrong */
	}
	wait_for_completion_interruptible(&urb_done);
}

/* 使用批量传输 向 usb设备发送 数据.
 *
 * @ep_num: 端点号, 需要为批量输出端点.*/
static void usb_bulk_send(struct usb_device *dev,
				unsigned char *iobuf, int buf_size, dma_addr_t iobuf_dma, int ep_num)
{
	pr_err("%s:in %d.\n",__func__,__LINE__);
	struct urb *urb;
	int pipe;
	int status = -1;
	struct completion urb_done;

	urb = usb_alloc_urb(0, GFP_KERNEL);

	pipe = usb_sndbulkpipe(dev, ep_num);

	usb_fill_bulk_urb(urb,
				     dev,
				     pipe,
					 iobuf,
					 buf_size,
					 usb_completion2,
				     &urb_done);

	urb->transfer_flags = 0;

	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
	urb->transfer_dma = iobuf_dma;

	init_completion(&urb_done);
	status = usb_submit_urb(urb, GFP_NOIO);
	if (status) {
		pr_err("%s:in %d. error\n",__func__,__LINE__);
		/* something went wrong */
	}
	wait_for_completion_interruptible(&urb_done);
}

typedef struct
{
    u32     dCBWSignature;
    #define CBWSIGNATURE    0x43425355
    u32     dCBWTag;
    u32     dCBWDataTransferLength;
    u8      bCBWFlags;
    #define CBWFLAGS_OUT    0x00
    #define CBWFLAGS_IN 0x80
    u8      bCBWLUN;
    u8      bCBWCBLength;
    #define CBWCDBLENGTH    16
    u8      CBWCDB[CBWCDBLENGTH];
} umass_bbb_cbw_t;               

typedef struct
{   
    u32     dCSWSignature;
    #define CSWSIGNATURE    0x53425355 
    u32     dCSWTag;
    u32     dCSWDataResidue;
    u8      bCSWStatus;
    #define CSWSTATUS_GOOD  0x0
    #define CSWSTATUS_FAILED 0x1
    #define CSWSTATUS_PHASE 0x2
} umass_bbb_csw_t;

static u32 cbwtag = 0; 

u8 usb_disk_inquiry(struct usb_device *dev)
{   
	pr_err("%s:in %d.\n",__func__,__LINE__);
	u8 device_addr = dev->devnum;
    umass_bbb_cbw_t *cbw;
    umass_bbb_csw_t *csw;

    dma_addr_t iobuf_dma;
	unsigned char *iobuf = usb_alloc_coherent(dev, sizeof(umass_bbb_cbw_t), GFP_ATOMIC, &iobuf_dma);

	u8 rcv_buf_size = 36;
	dma_addr_t rcv_buf_dma;
	unsigned char *rcv_buf = usb_alloc_coherent(dev, rcv_buf_size, GFP_ATOMIC, &rcv_buf_dma);

	dma_addr_t ret_buf_dma;
	unsigned char *ret_buf = usb_alloc_coherent(dev, sizeof(umass_bbb_csw_t), GFP_ATOMIC, &ret_buf_dma);

	cbw = (umass_bbb_cbw_t *)iobuf;
	csw = (umass_bbb_csw_t *)ret_buf;

    memset(cbw->CBWCDB, 0, CBWCDBLENGTH);
    
    cbw->dCBWSignature = CBWSIGNATURE;
    cbw->dCBWTag = cbwtag++;
    cbw->dCBWDataTransferLength = 36;
    cbw->bCBWFlags = 0x80; /* 请求数据输入 */
    cbw->bCBWLUN = 0; /* 目标lun的编号. 一般U盘只有一个lun,即其编号为0 */
    cbw->bCBWCBLength = 12; /* 命令长度. */

    /* 命令码 */
    cbw->CBWCDB[0] = 0x12;
    cbw->CBWCDB[1] = cbw->bCBWLUN<<5;
    cbw->CBWCDB[4] = cbw->dCBWDataTransferLength;
    
    /* 命令阶段 */
    /* sizeof(cbw)值是32, 与实际31不符. 导致device解析命令失败.... */
	//ehci_usb_bulk_trans(device_addr, ed_out, &cbw, 31, &out_toggle);
	usb_bulk_send(dev, iobuf, 31, iobuf_dma, 2);

    /* 数据阶段 */ /* 这里buffer的数据就用usb分析仪看吧，不打印了。。 */
	//ehci_usb_bulk_trans(device_addr, ed_in, buffer, sizeof(buffer), &in_toggle);
	usb_bulk_recv(dev, rcv_buf, rcv_buf_size, rcv_buf_dma, 1);

    /* 状态阶段, toggle必须为1, 否则报cc=3(toggle不符) */
	//ehci_usb_bulk_trans(device_addr, ed_in, &csw, 13, &in_toggle);
	usb_bulk_recv(dev, ret_buf, 13, ret_buf_dma, 1);

	pr_err("%s:in %d. rcv_buf 0x%x\n",__func__,__LINE__, rcv_buf[0]);
	pr_err("%s:in %d. rcv_buf 0x%x\n",__func__,__LINE__, rcv_buf[1]);
	pr_err("%s:in %d. rcv_buf 0x%x\n",__func__,__LINE__, rcv_buf[2]);
	pr_err("%s:in %d. rcv_buf 0x%x\n",__func__,__LINE__, rcv_buf[3]);
    return csw->bCSWStatus;
}

static void usb_gadget_zero_probe(struct usb_device *dev)
{
	pr_err("%s:in %d.\n",__func__,__LINE__);

	int i = 0;

	int buf_size = 256; /* 接收数据的size必须为ep的max packet size...否则usb slave 会重传. */
    dma_addr_t iobuf_dma;
	unsigned char *iobuf = usb_alloc_coherent(dev, buf_size, GFP_ATOMIC, &iobuf_dma);

	int sbuf_size = 5;
    dma_addr_t siobuf_dma;
	unsigned char *siobuf = usb_alloc_coherent(dev, sbuf_size, GFP_ATOMIC, &siobuf_dma);

	//usb_driver_set_configuration(dev, 2);

	usb_set_interface(dev, 0, 0);

	//usb_reset_endpoint(dev, 1);
	//usb_reset_endpoint(dev, 2);

#if 1
	for(i=0; i<4; i++){
		usb_bulk_recv(dev, iobuf, buf_size, iobuf_dma, 1);
		pr_err("iobuf 0x%x\n", iobuf[0]);
	}
#endif
#if 0
	siobuf[0] = 1;
	siobuf[1] = 2;
	siobuf[2] = 3;
	usb_bulk_send(dev, siobuf, sbuf_size, siobuf_dma, 2);
	usb_bulk_recv(dev, iobuf, buf_size, iobuf_dma, 1);
	pr_err("iobuf 0x%x\n", iobuf[0]);
	pr_err("iobuf 0x%x\n", iobuf[1]);
	pr_err("iobuf 0x%x\n", iobuf[2]);

	siobuf[0] = 4;
	siobuf[1] = 5;
	siobuf[2] = 6;
	usb_bulk_send(dev, siobuf, sbuf_size, siobuf_dma, 2);
	usb_bulk_recv(dev, iobuf, buf_size, iobuf_dma, 1);
	pr_err("iobuf 0x%x\n", iobuf[0]);
	pr_err("iobuf 0x%x\n", iobuf[1]);
	pr_err("iobuf 0x%x\n", iobuf[2]);

	siobuf[0] = 7;
	siobuf[1] = 8;
	siobuf[2] = 9;
	usb_bulk_send(dev, siobuf, sbuf_size, siobuf_dma, 2);
	usb_bulk_recv(dev, iobuf, buf_size, iobuf_dma, 1);
	pr_err("iobuf 0x%x\n", iobuf[0]);
	pr_err("iobuf 0x%x\n", iobuf[1]);
	pr_err("iobuf 0x%x\n", iobuf[2]);

	siobuf[0] = 71;
	siobuf[1] = 82;
	siobuf[2] = 93;
	usb_bulk_send(dev, siobuf, sbuf_size, siobuf_dma, 2);
	usb_bulk_recv(dev, iobuf, buf_size, iobuf_dma, 1);
	pr_err("iobuf 0x%x\n", iobuf[0]);
	pr_err("iobuf 0x%x\n", iobuf[1]);
	pr_err("iobuf 0x%x\n", iobuf[2]);
#endif
}

static void udisk_probe(struct usb_device *dev)
{
	unsigned char *iobuf = NULL;
	dma_addr_t	iobuf_dma = 0;
	struct usb_ctrlrequest	*cr = NULL;
	struct urb *urb;
	int buf_size = 1;
	int ctrl_pipe;
	int status = -1;
	struct completion urb_done;

	print_device_desc(&dev->descriptor);
	usb_ctrl_tran(dev, 0x80, 0x06, 0x0100, 0, 8); /* get device desc */
	usb_ctrl_tran(dev, 0x21, 0xFF, 0x0, 0, 0); /* reset udisk */
	mdelay(150);
#if 0
	usb_ctrl_tran(dev, 0x2, 0x1, 0x0, 1, 0); /* reset ep 1 */
	mdelay(150);
	usb_ctrl_tran(dev, 0x2, 0x1, 0x0, 2, 0); /* reset ep 2 */
	mdelay(150);
#endif

	/* u盘上电了, 只能查询一次.. */
	usb_disk_inquiry(dev);
}

static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	pr_err("%s:in %d.\n",__func__,__LINE__);
	struct usb_device *dev = interface_to_usbdev(intf);
	unsigned char *iobuf = NULL;
	dma_addr_t	iobuf_dma = 0;
	struct usb_ctrlrequest	*cr = NULL;
	struct urb *urb;
	int buf_size = 1;
	int ctrl_pipe;
	int status = -1;
	struct completion urb_done;

	//udisk_probe(dev);
	usb_gadget_zero_probe(dev);
	return 0;
}

static void usb_mouse_disconnect(struct usb_interface *intf)
{
	pr_err("%s:in %d.\n",__func__,__LINE__);

	return 0;
	struct usb_mouse *mouse = usb_get_intfdata (intf);

	usb_set_intfdata(intf, NULL);
	if (mouse) {
		usb_kill_urb(mouse->irq);
		input_unregister_device(mouse->dev);
		usb_free_urb(mouse->irq);
		usb_free_coherent(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
		kfree(mouse);
	}
}

static struct usb_device_id usb_mouse_id_table [] = {
	{USB_DEVICE(0x0951,0x1665)}, /* udisk */
	{USB_DEVICE(0x0525,0xa4a0)}, /* gadget_zero */
	{USB_DEVICE(0x0525,0xa4a5)}, /* gadget_mass storage */
	{ }	/* Terminating entry */
};

MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);

static struct usb_driver usb_mouse_driver = {
	.name		= "usbmouse",
	.probe		= usb_mouse_probe,
	.disconnect	= usb_mouse_disconnect,
	.id_table	= usb_mouse_id_table,
};

module_usb_driver(usb_mouse_driver);
